﻿/*
*       Developed by Justin Mead
*       ©2009 MeadMiracle
*		www.meadmiracle.com / meadmiracle@gmail.com
*       Version 1.0
*       Testing: IE7/Windows XP
*                Firefox/Windows XP
*       Licensed under the Creative Commons GPL http://creativecommons.org/licenses/GPL/2.0/
*
*       OPTIONS LISTING:
*           *box1View, box2View         - the id attributes of the VISIBLE listboxes
*           *box1Storage, box2Storage   - the id attributes of the HIDDEN listboxes (used for filtering)
*           *box1Filter, box2Filter     - the id attributes of the textboxes used to filter the lists
*           *box1Clear, box2Clear       - the id attributes of the elements used to clear/reset the filters
*           *box1Counter, box2Counter   - the id attributes of the elements used to display counts of visible/total items (used when filtering)
*           *to1, to2                   - the id attributes of the elements used to transfer only selected items between boxes
*           *allTo1, allTo2             - the id attributes of the elements used to transfer ALL (visible) items between boxes
*           *transferMode               - the type of transfer to perform on items (see heading TRANSFER MODES)
*           *sortBy                     - the attribute to use when sorting items (values: 'text' or 'value')
*           *useFilters                 - allow the filtering of items in either box (true/false)
*           *useCounters                - use the visible/total counters (true/false)
*           *useSorting                 - sort items after executing a transfer (true/false)
*
*       All options have default values, and as such, are optional.  Check the 'wsettings' JSON object below to see the defaults.
*
*       TRANSFER MODES:
*           * 'move' - In this mode, items will be removed from the box in which they currently reside and moved to the other box. This is the default.
*           * 'copy' - In this mode, items in box 1 will ALWAYS remain in box 1 (unless they are hidden by filtering).  When they are selected for transfer
*                      they will be copied to box 2 and will be given the class 'copiedOption' in box 1 (my default styling for this class is yellow background
*                      but you may choose whatever styling suits you).  If they are then transferred from box 2, they disappear from box 2, and the 'copiedOption'
*                      class is removed from the corresponding option in box 1.
*
*/

/*
* Modifier : Do Dinh Dong
* Date     : 12/07/2009
* Note     : Add more configuration option for handle many dual list on one page
* Reason   : Current use only one varial to handle dual list, first options will be overwrited by later options
*/

(function($) {
	var wsettings;
	var onSort;
	var wonSort;

	//the main method that the end user will execute to setup the DLB
	$.wconfigureBoxes = function(wgroup1, wgroup2, options) {
		//define default wsettings
		wsettings = {
			box1View: 'box1View',
			box1Storage: 'box1Storage',
			box1Filter: 'box1Filter',
			box1Clear: 'box1Clear',
			box1Counter: 'box1Counter',
			box2View: 'box2View',
			box2Storage: 'box2Storage',
			box2Filter: 'box2Filter',
			box2Clear: 'box2Clear',
			box2Counter: 'box2Counter',
			to1: 'to1',
			allTo1: 'allTo1',
			to2: 'to2',
			allTo2: 'allTo2',
			transferMode: 'move',
			sortBy: 'text',
			useFilters: true,
			useCounters: true,
			useSorting: true
		};

		//merge default wsettings w/ user defined wsettings (with user-defined wsettings overriding defaults)
		$.extend(wsettings, options);

		//define box groups
		wgroup1 = {
			view: wsettings.box1View,
			storage: wsettings.box1Storage,
			filter: wsettings.box1Filter,
			clear: wsettings.box1Clear,
			counter: wsettings.box1Counter
		};
		wgroup2 = {
			view: wsettings.box2View,
			storage: wsettings.box2Storage,
			filter: wsettings.box2Filter,
			clear: wsettings.box2Clear,
			counter: wsettings.box2Counter
		};

		//define sort function
		if (wsettings.sortBy == 'text') {
			onSort = function(a, b) {
				var aVal = a.text.toLowerCase();
				var bVal = b.text.toLowerCase();
				if (aVal < bVal) { return -1; }
				if (aVal > bVal) { return 1; }
				return 0;
			};
			wonSort = function(a, b) {
				var aVal = $('#' + a.id.replace('li', 'span')).attr('innerHTML').toLowerCase();
				var bVal = $('#' + b.id.replace('li', 'span')).attr('innerHTML').toLowerCase();
				if (aVal < bVal) { return -1; }
				if (aVal > bVal) { return 1; }
				return 0;
			};
		} else {
			onSort = function(a, b) {
				var aVal = a.value.toLowerCase();
				var bVal = b.value.toLowerCase();
				if (aVal < bVal) { return -1; }
				if (aVal > bVal) { return 1; }
				return 0;
			};
		}

		//configure events
		if (wsettings.useFilters) {
			$('#' + wgroup1.filter).keyup(function() {
				Filter(wgroup1);
			});
			$('#' + wgroup2.filter).keyup(function() {
				Filter(wgroup2);
			});
			$('#' + wgroup1.clear).click(function() {
				ClearFilter(wgroup1);
			});
			$('#' + wgroup2.clear).click(function() {
				ClearFilter(wgroup2);
			});
		}
		//$('#' + wgroup2.view).dblclick(function() {
		//	RemoveSelected(wgroup2, wgroup1);
		//});
		$('#' + wsettings.to1).click(function() {
			RemoveSelected(wgroup2, wgroup1);
		});
		$('#' + wsettings.allTo1).click(function() {
			RemoveAll(wgroup2, wgroup1);
		});

		$('#' + wgroup1.view).dblclick(function() {
			MoveSelected(wgroup1, wgroup2);
		});
		$('#' + wsettings.to2).click(function() {
			MoveSelected(wgroup1, wgroup2);
		});
		$('#' + wsettings.allTo2).click(function() {
			MoveAll(wgroup1, wgroup2);
		});

		//initialize the counters
		if (wsettings.useCounters) {
			UpdateLabel(wgroup1);
			UpdateLabel(wgroup2);
		}

		//pre-sort item sets
		if (wsettings.useSorting) {
			SortOptions(wgroup1);
			wSortOptions(wgroup2);
		}

		//hide the storage boxes
		$('#' + wgroup1.storage + ',#' + wgroup2.storage).css('display', 'none');
	};

	function UpdateLabel(group) {
		var showingCount = $("#" + group.view + " option").size();
		var hiddenCount = $("#" + group.storage + " option").size();
		$("#" + group.counter).text('Showing ' + showingCount + ' of ' + (showingCount + hiddenCount));
	}

	function Filter(group) {
		var filterLower;
		if (wsettings.useFilters) {
			filterLower = $('#' + group.filter).val().toString().toLowerCase();
		} else {
			filterLower = '';
		}
		$('#' + group.view + ' option').filter(function(i) {
			var toMatch = $(this).text().toString().toLowerCase();
			return toMatch.indexOf(filterLower) == -1;
		}).appendTo('#' + group.storage);
		$('#' + group.storage + ' option').filter(function(i) {
			var toMatch = $(this).text().toString().toLowerCase();
			return toMatch.indexOf(filterLower) != -1;
		}).appendTo('#' + group.view);
		try {
			$('#' + group.view + ' option').removeAttr('selected');
		}
		catch (ex) {
			//swallow the error for IE6
		}
		if (wsettings.useSorting) { SortOptions(group); }
		if (wsettings.useCounters) { UpdateLabel(group); }
	}

	function SortOptions(group) {
		var $toSortOptions = $('#' + group.view + ' option');
		$toSortOptions.sort(onSort);
		$('#' + group.view).empty().append($toSortOptions);
	}
	function wSortOptions(group) {
		var $toSortOptions = $('#' + group.view + ' li');
		$toSortOptions.sort(wonSort);
		$('#' + group.view).empty().append($toSortOptions);
	}

	function MoveSelected(fromGroup, toGroup) {
		if (IsMoveMode()) {
			var tempItem = $('#' + fromGroup.view + ' option:selected');
			$('#' + fromGroup.view + ' option:selected').remove();
			$newItem = $('<li id="li_' + toGroup.view + '_' + tempItem.attr('value') + '" />');
			$newItem.append('<span id="span_' + toGroup.view + '_' + tempItem.attr('value') + '" title="' + tempItem.attr('innerHTML') + '"ondblclick="RemoveSelected(this, \'' + fromGroup.view + '\');"> ' + tempItem.attr('innerHTML') + '</span>&nbsp;');
			$newSelect = $('<select id="select_' + toGroup.view + '_' + tempItem.attr('value') + '" />');
			for (i = 0; i < 10; i++) {
				$option = $('<option />');
				$option.attr('value', i);
				$option.attr('innerHTML', i);
				$newSelect.append($option);
			}
			$newItem.append($newSelect);
			$('#' + toGroup.view).append($newItem);
		} else {
			$('#' + fromGroup.view + ' option:selected:not([class*=copiedOption])').clone().appendTo('#' + toGroup.view).end().end().addClass('copiedOption');
		}
		try {
			$('#' + fromGroup.view + ' option').removeAttr('selected');
		}
		catch (ex) {
			//swallow the error for IE6
		}
		wSortOptions(toGroup);
		if (wsettings.useCounters) { UpdateLabel(fromGroup); }
	}

	function MoveAll(fromGroup, toGroup) {
		if (IsMoveMode()) {
			$('#' + fromGroup.view + ' option').appendTo('#' + toGroup.view);
		} else {
			$('#' + fromGroup.view + ' option:not([class*=copiedOption])').clone().appendTo('#' + toGroup.view).end().end().addClass('copiedOption');
		}
		try {
			$('#' + fromGroup.view + ' option,#' + toGroup.view + ' option').removeAttr('selected');
		}
		catch (ex) {
			//swallow the error for IE6
		}
		Filter(toGroup);
		if (wsettings.useCounters) { UpdateLabel(fromGroup); }
	}

	function RemoveSelected(removeGroup, otherGroup) {
		try {
			$('#' + removeGroup.view + ' selected').remove();
		}
		catch (ex) {
			//swallow the error for IE6
		}
		$('#' + otherGroup.view + ' option.copiedOption').add('#' + otherGroup.storage + ' option.copiedOption').remove();
		$('#' + removeGroup.view + ' option').add('#' + removeGroup.storage + ' option').clone().addClass('copiedOption').appendTo('#' + otherGroup.view);
		Filter(otherGroup);
		if (wsettings.useCounters) { UpdateLabel(removeGroup); }
	}

	function RemoveAll(removeGroup, otherGroup) {
		$('#' + otherGroup.view + ' option.copiedOption').add('#' + otherGroup.storage + ' option.copiedOption').remove();
		try {
			$('#' + removeGroup.storage + ' option').clone().addClass('copiedOption').add('#' + removeGroup.view + ' option').appendTo('#' + otherGroup.view).removeAttr('selected');
		}
		catch (ex) {
			//swallow the error for IE6
		}
		Filter(otherGroup);
		if (wsettings.useCounters) { UpdateLabel(removeGroup); }
	}

	function ClearFilter(group) {
		$('#' + group.filter).val('');
		$('#' + group.storage + ' option').appendTo('#' + group.view);
		try {
			$('#' + group.view + ' option').removeAttr('selected');
		}
		catch (ex) {
			//swallow the error for IE6
		}
		if (wsettings.useSorting) { SortOptions(group); }
		if (wsettings.useCounters) { UpdateLabel(group); }
	}

	function IsMoveMode() {
		return wsettings.transferMode == 'move';
	}
})(jQuery);
function RemoveSelected(removeOjb, otherGroup) {
	var id = removeOjb.id.replace('span_','');
	var option = $('<option />');
	option.attr('value', id);
	option.attr('innerHTML', removeOjb.innerHTML.trim());
	option.attr('title', removeOjb.innerHTML.trim());
	try {
		$('#' + removeOjb.parentNode.id).remove();
	}
	catch (ex) {
		//swallow the error for IE6
	}
	$('#' + otherGroup).append(option);

	onSort = function(a, b) {
		var aVal = a.text.toLowerCase();
		var bVal = b.text.toLowerCase();
		if (aVal < bVal) { return -1; }
		if (aVal > bVal) { return 1; }
		return 0;
	};
	var $toSortOptions = $('#' + otherGroup + ' option');
	$toSortOptions.sort(onSort);
	$('#' + otherGroup).empty().append($toSortOptions);
}

